home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / pc / UGPRG.ZIP / DENTHOR / TUT17.DOC < prev    next >
Encoding:
Text File  |  1996-07-27  |  36.2 KB  |  1,133 lines

  1.                    ╒═══════════════════════════════╕
  2.                    │         W E L C O M E         │
  3.                    │  To the VGA Trainer Program   │ │
  4.                    │              By               │ │
  5.                    │      DENTHOR of ASPHYXIA      │ │ │
  6.                    ╘═══════════════════════════════╛ │ │
  7.                      ────────────────────────────────┘ │
  8.                        ────────────────────────────────┘
  9.  
  10.                            --==[ PART 17 ]==--
  11.  
  12.  
  13.  
  14. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  15. ■ Introduction
  16.  
  17. Hi there everybody. It's a new year, but the parties are over and it's time
  18. to get coding again!
  19.  
  20. My mailserver died. Various sysadmins decided it was time to upgrade the
  21. OS, and wound up nuking the hard drive :-( ... this means that request-list
  22. is not working at the moment, and I have probably lost lots of mail.
  23.  
  24. denthor@beastie.cs.und.ac.za is still the account to write to, and
  25. hopefully the mailserver will be back up in the near future.
  26.  
  27. There are various C/C++ conversions of my trainer, best of which seem to be
  28. those by Snowman ... he runs through the text files with C++ updates (and
  29. seems to point out my previous mistakes with glee ;-), as well is giving a
  30. fully documented C++ conversion of the source ... very nice stuff.
  31.  
  32. Also, my trainers are being put on a World Wide Web site ... it is still
  33. under construction, but go to http://www.cit.gu.edu.au/~rwong
  34. my site is at http://goth.vironix.co.za/~denthor ... it is currently pretty
  35. awful, anyone want to write a nice one for me? ;)
  36.  
  37. I have just about finished Asphyxia's new game, I will let you all know
  38. when it is completed.
  39.  
  40. Tut 16 dies with large bitmaps ... the way to sort this out is to decrease
  41. the accuracy of the fixed point from 256 to 128 ... then you can have
  42. bitmaps up to 512 pixels wide. I will be putting an updated scale routine
  43. in the gfx4.pas unit.
  44.  
  45. This tutor is on a few demo effects (pixel morphs and static) ... after
  46. this one, I will go on to more theory ... perhaps some more 3d stuff, such
  47. as gourad shading etc. Comments?
  48.  
  49.  
  50. If you would like to contact me, or the team, there are many ways you
  51. can do it : 1) Write a message to Grant Smith/Denthor/Asphyxia in private mail
  52.                   on the ASPHYXIA BBS.
  53.             2) Write to :  Grant Smith
  54.                            P.O.Box 270 Kloof
  55.                            3640
  56.                            Natal
  57.                            South Africa
  58.             3) Call me (Grant Smith) at (031) 73 2129 (leave a message if you
  59.                   call during varsity). Call +27-31-73-2129 if you call
  60.                   from outside South Africa. (It's YOUR phone bill ;-))
  61.             4) Write to denthor@beastie.cs.und.ac.za in E-Mail.
  62.             5) Write to asphyxia@beastie.cs.und.ac.za to get to all of
  63.                us at once.
  64.  
  65. NB : If you are a representative of a company or BBS, and want ASPHYXIA
  66.        to do you a demo, leave mail to me; we can discuss it.
  67. NNB : If you have done/attempted a demo, SEND IT TO ME! We are feeling
  68.         quite lonely and want to meet/help out/exchange code with other demo
  69.         groups. What do you have to lose? Leave a message here and we can work
  70.         out how to transfer it. We really want to hear from you!
  71.  
  72. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  73. ■  Pixel Morphing
  74.  
  75. Have you ever lain down on your back in the grass and looked up at the
  76. cloudy sky? If you have, you have probably seen the clouds move together
  77. and create wonderful shapes ... that cloud plus that cloud together make a
  78. whale ... a ship ... a face etc.
  79.  
  80. We can't quite outdo mother nature, but we can sure give it a shot. The
  81. effect I am going to show you is where various pixels at different starting
  82. points move together and create an overall picture.
  83.  
  84. The theory behind it is simple : Each pixel has bits of data associated
  85. with it, most important of which is as follows :
  86.  
  87. This is my color
  88. This is where I am
  89. This is where I want to be.
  90.  
  91. The pixel, keeping it's color, goes from where it is to where it wants to
  92. be. Our main problem is _how_ it moves from where it is to where it wants
  93. to be. A obvious approach would be to say "If it's destination is above it,
  94. decrement it's y value, if the destination is to the left, decrement it's x
  95. value and so on."
  96.  
  97. This would be bad. The pixel would only ever move at set angles, as you can
  98. see below :
  99.  
  100.                 Dest   O-----------------\
  101.                                            \  <--- Path
  102.                                              \
  103.                                                \
  104.                                                 O Source
  105.  
  106. Doesn't look very nice, does it? The pixels would also take different times
  107. to get to their destination, whereas we want them to reach their points at
  108. the same time, ie :
  109.  
  110.      Dest 1   O-------------------------------O Source 1
  111.      Dest 2   O-----------------O Source 2
  112.  
  113. Pixels 1 and 2 must get to their destinations at the same time for the best
  114. effect. The way this is done by defining the number of frames or "hops"
  115. needed to get from source to destination. For example, we could tell pixel
  116. one it is allowed 64 hops to get to it's destination, and the same for
  117. point 2, and they would both arrive at the same time, even though pixel 2
  118. is closer.
  119.  
  120. The next question, it how do we move the pixels in a straight line? This is
  121. easier then you think...
  122.  
  123. Let us assume that for each pixel, x1,y1 is where it is, and x2,y2 is where
  124. it wants to be.
  125.  
  126.    (x2-x1) = The distance on the X axis between the two points
  127.    (y2-y1) = The distance on the Y axis between the two points
  128.  
  129. If we do the following :
  130.  
  131.   dx := (x2-x1)/64;
  132.  
  133. we come out with a value in dx wich is very useful. If we added dx to x1 64
  134. times, the result would be x2! Let us check...
  135.  
  136.   dx = (x2-x1)/64
  137.   dx*64 = x2-x1         { Multiply both sides by 64 }
  138.   dx*64+x1 = x2         { Add x1 to both sides }
  139.  
  140. This is high school math stuff, and is pretty self explanitory. So what we
  141. have is the x movement for every frame that the pixel has to undergo. We
  142. find the y movement in the same manner.
  143.  
  144.   dy := (y2-y1)/64;
  145.  
  146. So our program is as follows :
  147.  
  148.   Set x1,y1 and x2,y2 values
  149.   dx:= (x2-x1)/64;
  150.   dy:= (y2-y1)/64;
  151.  
  152.   for loop1:=1 to 64 do BEGIN
  153.     putpixel (x1,y1)
  154.     wait;
  155.     clear pixel (x1,y1);
  156.     x1:=x1+dx;
  157.     y1:=y1+dy;
  158.   END;
  159.  
  160. If there was a compiler that could use the above pseudocode, it would move
  161. the pixel from x1,y1 to x2,y2 in 64 steps.
  162.  
  163. So, what we do is set up an array of many pixels with this information, and
  164. move them all at once ... viola, we have pixel morphing! It is usually best
  165. to use a bitmap which defines the color and destination of the pixels, then
  166. randomly scatter them around the screen.
  167.  
  168. Why not use pixel morphing on a base object in 3d? It would be the work of
  169. a moment to add in a Z axis to the above.
  170.  
  171. The sample program uses fixed point math in order to achieve high speeds,
  172. but it is basically the above algorithm.
  173.  
  174.  
  175. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  176. ■  Static
  177.  
  178. A static screen was one of the first effects Asphyxia ever did. We never
  179. actually released it because we couldn't find anywhere it would fit. Maybe
  180. you can.
  181.  
  182. The easiest way to get a sreen of static is to tune your TV into an unused
  183. station ... you even get the cool noise effect too. Those people who build
  184. TV's really know how to code ;-)
  185.  
  186. For us on a PC however, it is not as easy to generate a screen full of
  187. static (unless you desperately need a new monitor)
  188.  
  189. What we do is this :
  190.  
  191. Set colors 1-16 to various shades of grey.
  192. Fill the screen up with random pixels between colors 1 and 16
  193. Rotate the pallette of colors 1 to 16.
  194.  
  195. That's it! You have a screenfull of static! To get two images in one static
  196. screen, all you need to do is fade up/down the specific colors you are
  197. using for static in one of the images.
  198.  
  199. A nice thing about a static screen is that it is just pallette rotations
  200. ... you can do lots of things in the foreground at the same time (such as a
  201. scroller).
  202.  
  203. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  204. ■  In closing
  205.  
  206. Well, that is about it ... as I say, I will be doing more theory stuff in
  207. future, as individual demo effects can be thought up if you know the base
  208. stuff.
  209.  
  210. Note the putpixel in this GFX3.PAS unit ... it is _very_ fast .. but
  211. remember, just calling a procedure eats clock ticks... so imbed putpixels
  212. in your code if you need them. Most of the time a putpixel is not needed
  213. though.
  214.  
  215. PCGPE ][ will be out on the 10th of Feburary. All the new tutors will be on
  216. it (if you aren't reading this from it right now! ;-) ... grab a copy of
  217. it, it is a very useful ting to have handy.
  218.  
  219. I have found out that these tutors have been distributed inside paper
  220. magazines ... please remember that Denthor and Asphyxia retain full
  221. copyright to the series (as mentioned earlier in the series), and if you
  222. want to use a version in a magazine, CONTACT ME FIRST ... I will probably
  223. also modify it/cut out various unneccesary things ... other then that, you
  224. must not alter the files without my permission, or at least leave a copy of
  225. the origional with the update. Maybe I could even start up a nice column
  226. for some magazine or other :)
  227.  
  228. Sorry 'bout that, but it had to be said ...
  229.  
  230. I am writing a column for the Demuan list, a Florida-based electronic
  231. magazine ... pick it up off ftp.eng.ufl.edu ... I have written various
  232. articles, all bordering on quote-like design.
  233.  
  234. There are more BBS's to be added to the list at the end, but I don't have
  235. them here... this tut has taken long enough ;-)
  236.  
  237. Byeeeee....
  238.   - Denthor
  239.  
  240. The following are official ASPHYXIA distribution sites :
  241.  
  242. ╔══════════════════════════╦════════════════╦═════╗
  243. ║BBS Name                  ║Telephone No.   ║Open ║
  244. ╠══════════════════════════╬════════════════╬═════╣
  245. ║ASPHYXIA BBS #1           ║+27-31-765-5312 ║ALL  ║
  246. ║ASPHYXIA BBS #2           ║+27-31-765-6293 ║ALL  ║
  247. ║C-Spam BBS                ║410-531-5886    ║ALL  ║
  248. ║POP!                      ║+27-12-661-1257 ║ALL  ║
  249. ║Soul Asylum               ║+358-0-5055041  ║ALL  ║
  250. ║Wasted Image              ║407-838-4525    ║ALL  ║
  251. ║Reckless Life             ║351-01-716 67 58║ALL  ║
  252. ║Mach 5 BBS                ║+1 319-355-7336 ║ALL  ║
  253. ╚══════════════════════════╩════════════════╩═════╝
  254.  
  255. Leave me mail if you want to become an official Asphyxia BBS
  256. distribution site.
  257. {$X+}
  258. USES crt,gfx3;
  259.  
  260. Const jump = 64;       { Number of pixels active at once }
  261.       sjump = 6;       { 1 shl 6 = 64 }
  262.  
  263. TYPE
  264.         FontDat = Array [' '..'Z',1..16,1..16] of byte; {Our main font }
  265.         target = record
  266.                  herex,herey : integer;
  267.                  targx,targy : integer;
  268.                  dy,dx : integer;
  269.                  active : boolean;
  270.                  col : byte;
  271.                  num:integer;
  272.              END;
  273.         PixelDat = Array [1..4095] of target; { This is the maximum number
  274.                                                 of points we canb fit in a
  275.                                                 segment... }
  276.  
  277. VAR Font : ^FontDat;                          { Our nice font }
  278.     nextrow : ^PixelDat;
  279.     scr : array [' '..'Z',1..8,1..8] of byte; { The basic bios font }
  280.     Vir2 : VirtPtr;
  281.     Vaddr2 : Word;                            { Spare virtual screen }
  282.     counter:integer;
  283.     PosLoop:integer;
  284.     dir : boolean;
  285.     pathx,pathy:array [1..314] of integer;    { Path of origination }
  286.     arbpal : array [1..8,1..3] of byte;       { Used to remember certain
  287.                                                 colors }
  288.  
  289.  
  290.  
  291. {──────────────────────────────────────────────────────────────────────────}
  292. Procedure Bigmsg (x,y:integer;msg:string);
  293.   { This draws string msg to screen in the bios font, but bigger }
  294. VAR loop1,loop2,loop3,loop4,loop5:integer;
  295. BEGIN
  296.   for loop1:=1 to length (msg) do
  297.     for loop2:=1 to 8 do
  298.       for loop3:=1 to 8 do
  299.         if (scr[msg[loop1],loop3,loop2]<>0) then BEGIN
  300.           for loop4:=1 to 4 do
  301.             for loop5:=1 to 8 do
  302.               putpixel (x+(loop1*32)+(loop2*4)+loop4,y+(loop3*8)+loop5,
  303.                 getpixel (x+(loop1*32)+(loop2*4)+loop4,y+(loop3*8)+loop5,vaddr2)+51,vaddr);
  304.         END;
  305. END;
  306.  
  307.  
  308.  
  309.  
  310. {──────────────────────────────────────────────────────────────────────────}
  311. Procedure Static;
  312.   { This moves the static and tunes in to our background logo }
  313. VAR loop1,loop2,count,count2,count3:integer;
  314. BEGIN
  315.   flip (vaddr2,vaddr);
  316.   Bigmsg (0,60,'ASPHYXIA');
  317.   flip (vaddr,vga);
  318.   count:=0;
  319.   count2:=0;
  320.   for loop2:=1 to 100 do BEGIN
  321.     waitretrace;
  322.     for loop1:=99 to 150 do BEGIN
  323.       count:=random (64);
  324.       pal (loop1,count,count,count);
  325.     END;
  326.     for loop1:=150 to 201 do BEGIN
  327.       count:=random (64);
  328.       pal (loop1,count,count,count);
  329.     END;
  330.   END;   { Do the static for a while }
  331.  
  332.   repeat
  333.     inc (count);
  334.     if count>10 then BEGIN
  335.       count:=0;
  336.       inc (count2);
  337.     END;
  338.     waitretrace;
  339.     for loop1:=99 to 150 do BEGIN
  340.       count3:=random (64-count2);
  341.       if count3<0 then count3:=0;
  342.       pal (loop1,count3,count3,count3);
  343.     END;
  344.     for loop1:=150 to 201 do BEGIN
  345.       count3:=random (64);
  346.       count3:=count3+count2;
  347.       if count3>63 then count3:=63;
  348.       pal (loop1,count3,count3,count3);
  349.     END;
  350.   until count2>63; { Static fade in Asphyxia logo }
  351.  
  352.   delay (500);
  353.   for loop1:=30 to 62 do BEGIN
  354.     line (0,loop1*2,319,loop1*2,0,vga);
  355.     delay (5);
  356.   END;
  357.   for loop1:=62 downto 30 do BEGIN
  358.     line (0,loop1*2+1,319,loop1*2+1,0,vga);
  359.     delay (5);
  360.   END;  { Erase logo with lines }
  361.   delay (1000);
  362.   while keypressed do readkey;
  363. END;
  364.  
  365.  
  366. {──────────────────────────────────────────────────────────────────────────}
  367. Procedure Fadeup;
  368.   { This fades up the pallette to white }
  369. VAR loop1,loop2:integer;
  370.     Tmp : Array [1..3] of byte;
  371. BEGIN
  372.   For loop1:=1 to 64 do BEGIN
  373.     WaitRetrace;
  374.     For loop2:=0 to 255 do BEGIN
  375.       Getpal (loop2,Tmp[1],Tmp[2],Tmp[3]);
  376.       If Tmp[1]<63 then inc (Tmp[1]);
  377.       If Tmp[2]<63 then inc (Tmp[2]);
  378.       If Tmp[3]<63 then inc (Tmp[3]);
  379.       Pal (loop2,Tmp[1],Tmp[2],Tmp[3]);
  380.     END;
  381.   END;
  382. END;
  383.  
  384.  
  385. {──────────────────────────────────────────────────────────────────────────}
  386. Procedure FadeTo (name:string);
  387.   { This procedure fades the screen to name ... if you use this for yourself,
  388.     you will need to cut out the extra stuff I do in here specific to this
  389.     program }
  390. VAR loop1,loop2:integer;
  391.     tmp,pall2:array[0..255,1..3] of byte;
  392.     f:file;
  393. BEGIN
  394.   assign (f,name);
  395.   reset (f,1);
  396.   blockread (f,pall2,768);
  397.   close (f);
  398.   for loop1:=100 to 150 do BEGIN
  399.     pall2[loop1,1]:=loop1-100;
  400.     pall2[loop1,2]:=loop1-100;
  401.     pall2[loop1,3]:=loop1-100;
  402.   END;  { Set the background colors }
  403.   waitretrace;
  404.   for loop1:=0 to 255 do
  405.     getpal (loop1,tmp[loop1,1],tmp[loop1,2],tmp[loop1,3]);
  406.  
  407.   For loop1:=1 to 64 do BEGIN
  408.     For loop2:=0 to 255 do BEGIN
  409.       If Tmp[loop2,1]<Pall2[loop2,1] then inc (Tmp[loop2,1]);
  410.       If Tmp[loop2,2]<Pall2[loop2,2] then inc (Tmp[loop2,2]);
  411.       If Tmp[loop2,3]<Pall2[loop2,3] then inc (Tmp[loop2,3]);
  412.       If Tmp[loop2,1]>Pall2[loop2,1] then dec (Tmp[loop2,1]);
  413.       If Tmp[loop2,2]>Pall2[loop2,2] then dec (Tmp[loop2,2]);
  414.       If Tmp[loop2,3]>Pall2[loop2,3] then dec (Tmp[loop2,3]);
  415.     END;
  416.     WaitRetrace;
  417.     for loop2:=0 to 255 do
  418.       pal (loop2,tmp[loop2,1],tmp[loop2,2],tmp[loop2,3]);
  419.   END;
  420. END;
  421.  
  422.  
  423. {──────────────────────────────────────────────────────────────────────────}
  424. Procedure Show (x,y:integer;ch:string);
  425.   { This dumps string ch to screen at x,y in our main font }
  426. VAR loop1,loop2,loop3:integer;
  427. BEGIN
  428.   for loop3:=1 to length (ch) do
  429.     For loop1:=1 to 16 do
  430.       for loop2:=1 to 16 do
  431.         if Font^[ch[loop3],loop2,loop1]<>0 then
  432.           putpixel (x+loop1+(loop3*17),y+loop2,getpixel (x+loop1+(loop3*17),y+loop2,vaddr2)+51,VGA);
  433. END;
  434.  
  435.  
  436. {──────────────────────────────────────────────────────────────────────────}
  437. Procedure Eye_Popper;
  438.   { This fades up the colors used in our main font }
  439. VAR Loop1,loop2:integer;
  440.     tmp : array [1..3] of byte;
  441. BEGIN
  442.   if keypressed then exit;
  443.   for loop1:=1 to 63 do
  444.     for loop2:=1 to 8 do BEGIN
  445.       Waitretrace;
  446.       Getpal (loop2,tmp[1],tmp[2],tmp[3]);
  447.       if tmp[1]<63 then inc (tmp[1]);
  448.       if tmp[2]<63 then inc (tmp[2]);
  449.       if tmp[3]<63 then inc (tmp[3]);
  450.       pal (loop2,tmp[1],tmp[2],tmp[3]);
  451.     END;
  452.   for loop1:=151 to 200 do
  453.     pal (loop1,63,63,63);
  454. END;
  455.  
  456.  
  457. {──────────────────────────────────────────────────────────────────────────}
  458. Procedure FadeOutText;
  459.   { This fades out the colors of our main font to the colors of the background
  460.     static }
  461. VAR Loop1,loop2:integer;
  462.     tmp : array [1..3] of byte;
  463. BEGIN
  464.   if keypressed then exit;
  465.   for loop1:=1 to 63 do BEGIN
  466.     Waitretrace;
  467.     for loop2:=151 to 200 do BEGIN
  468.       Getpal (loop2,tmp[1],tmp[2],tmp[3]);
  469.       if tmp[1]>loop2-151 then dec (tmp[1]);
  470.       if tmp[2]>loop2-151 then dec (tmp[2]);
  471.       if tmp[3]>loop2-151 then dec (tmp[3]);
  472.       pal (loop2,tmp[1],tmp[2],tmp[3]);
  473.     END;
  474.   END;
  475.   delay (100);
  476. END;
  477.  
  478.  
  479. {──────────────────────────────────────────────────────────────────────────}
  480. Procedure Move_Em_Out (num:integer;del:byte);
  481.   { This procedure runs through each pixel that is active and moves it closer
  482.     to its destination }
  483. VAR loop2:integer;
  484. BEGIN
  485.   if del<>0 then delay (del);
  486.   for loop2:=1 to num do
  487.     if nextrow^[loop2].active then with nextrow^[loop2] do BEGIN
  488.       putpixel (herex shr sjump,herey shr sjump,
  489.                 getpixel (herex shr sjump,herey shr sjump,vaddr),vga);
  490.         { Restore old bacground }
  491.       herex:=herex-dx;
  492.       herey:=herey-dy;  { Move pixel one step closer }
  493.       putpixel (herex shr sjump,herey shr sjump,col,vga); { Put down pixel }
  494.       dec (num);
  495.       if num=0 then BEGIN
  496.         active:=false;
  497.         putpixel (herex shr sjump,herey shr sjump,col,vaddr);
  498.       END;  { If destination reached, deactivate }
  499.     END;
  500. END;
  501.  
  502.  
  503. {──────────────────────────────────────────────────────────────────────────}
  504. Procedure Doletter (msg : char; dx,dy : integer);
  505.   { This procedure activates the pixels necessary to draw a letter }
  506. VAR loop1,loop2:integer;
  507.     x,y : Integer;
  508. BEGIN
  509.   if keypressed then exit;
  510.   for loop2:=1 to 16 do BEGIN
  511.     for loop1:=1 to 16 do     { Our font is 16x16 }
  512.       if Font^[msg,loop1,loop2]<>0 then BEGIN { Don't do black pixels }
  513.         if dir then PosLoop:=PosLoop+1
  514.           else PosLoop:=PosLoop-1;
  515.         if PosLoop=315 then PosLoop:=1;
  516.         if PosLoop=0 then PosLoop:=314;
  517.         X:=pathx[PosLoop]+160;
  518.         y:=pathy[PosLoop]+100;     { Find point of origination }
  519.  
  520.         nextrow^ [counter].herex:=x shl sjump;
  521.         nextrow^ [counter].herey:=y shl sjump;
  522.           { This is where I am }
  523.         nextrow^ [counter].targx:=(dx+loop2) shl sjump;
  524.         nextrow^ [counter].targy:=(dy+loop1) shl sjump;
  525.           { This is where I want to be }
  526.         nextrow^ [counter].dx:=(nextrow^[counter].herex-nextrow^[counter].targx) div jump;
  527.         nextrow^ [counter].dy:=(nextrow^[counter].herey-nextrow^[counter].targy) div jump;
  528.           { This is how I get there }
  529.         nextrow^ [counter].col:=Font^[msg,loop1,loop2];
  530.         nextrow^ [counter].active:=TRUE;
  531.         nextrow^ [counter].num:=jump;
  532.         move_em_out(jump,6);
  533.  
  534.         inc (counter);
  535.         if counter=jump+1 then counter:=1;
  536.       END;
  537.   END;
  538. END;
  539.  
  540.  
  541.  
  542. {──────────────────────────────────────────────────────────────────────────}
  543. Procedure DoPic;
  544.   { This procedure morphs in the tank }
  545. VAR f:file;
  546.     ch:byte;
  547.     count,loop1,loop2:integer;
  548.     ourpal : array [0..255,1..3] of byte;
  549. BEGIN
  550.   cls (vaddr,0);
  551.   getmem (nextrow,sizeof(nextrow^));
  552.   GetMem(Vir2,64000);
  553.   Vaddr2 := Seg(Vir2^);
  554.   for loop2:=1 to 4095 do
  555.     nextrow^[loop2].active:=false;
  556.  
  557.   assign (f,'tut17.cel');
  558.   reset (f,1);
  559.   seek (f,32);
  560.   blockread (f,ourpal,768);
  561.   for loop1:=0 to 255 do
  562.     pal (loop1,ourpal[loop1,1],ourpal[loop1,2],ourpal[loop1,3]);
  563.   count:=1;
  564.   for loop2:=1 to 60 do
  565.     for loop1:=1 to 160 do BEGIN
  566.       blockread (f,ch,1);     { Go through the pic, and activate non-black
  567.                                 pixels }
  568.       if ch<>0 then BEGIN
  569.         nextrow^ [count].herex:=random (320) shl sjump;
  570.         nextrow^ [count].herey:=random (200) shl sjump;
  571.           { This is where I am }
  572.         nextrow^ [count].targx:=(loop1+80) shl sjump;
  573.         nextrow^ [count].targy:=(loop2+70) shl sjump;
  574.           { This is where I want to be }
  575.         nextrow^ [count].dx:=(nextrow^[count].herex-nextrow^[count].targx) div jump;
  576.         nextrow^ [count].dy:=(nextrow^[count].herey-nextrow^[count].targy) div jump;
  577.           { This is how I get there }
  578.         nextrow^ [count].col:=ch;
  579.         nextrow^ [count].active:=TRUE;
  580.         nextrow^ [count].num:=jump;
  581.         inc (count);
  582.       END;
  583.   END;
  584.   close (f);
  585.   for loop1:=0 to 64 do
  586.     move_em_out (count,0);  { Move pixels to targets }
  587.   delay (2000);
  588.   fadeup;
  589. END;
  590.  
  591. {──────────────────────────────────────────────────────────────────────────}
  592. Procedure Init;
  593. VAR f:file;
  594.     loop1,loop2:integer;
  595.     loopie:real;
  596. BEGIN
  597.   getmem (Font,sizeof(Font^));
  598.  
  599.   for loop2:=1 to jump do
  600.     nextrow^[loop2].active:=false;
  601.  
  602.   Assign(f,'gods.Fnt');
  603.   Reset(f,1);
  604.   Blockread(F,Font^,SizeOf(Font^));
  605.   Close(f);
  606.  
  607.   assign (f,'biostext.dat');
  608.   reset (f,1);
  609.   Blockread (f,scr,sizeof (scr));
  610.   close (f);
  611.  
  612.   counter:=1;
  613.   PosLoop:=1;
  614.   dir:=true;
  615.   loopie:=0;
  616.   for loop1:=1 to 314 do BEGIN
  617.     loopie:=loopie+0.02;
  618.     pathX[loop1]:=round(150*cos (loopie));
  619.     pathy[loop1]:=round(90*sin (loopie));
  620.   END;    { Generate our path of origination }
  621.   cls (vga,0);
  622.   cls (vaddr,0);
  623.   cls (vaddr2,0);
  624.   for loop1:=0 to 319 do
  625.     for loop2:=0 to 199 do
  626.       putpixel (loop1,loop2,random (50)+100,vaddr2); { Fill the screen with static }
  627.   flip (vaddr2,vaddr);
  628.   flip (vaddr,vga);
  629.   fadeto ('game01.col');
  630.   for loop1:=1 to 8 do
  631.     getpal (loop1,arbpal[loop1,1],arbpal[loop1,2],arbpal[loop1,3]);
  632. END;
  633.  
  634.  
  635. {──────────────────────────────────────────────────────────────────────────}
  636. Procedure Play;
  637. VAR loop1,loop2:integer;
  638.     message : Array [1..10] of string;
  639. BEGIN
  640.   DoPic;
  641.   init;
  642.   while keypressed do readkey;
  643.              {[                 ]}
  644.   message[1]:='';
  645.   message[2]:='';
  646.   message[3]:='   PIXEL TEXT   ';
  647.   message[4]:='';
  648.   message[5]:='   A  ROUTINE';
  649.   message[6]:='';
  650.   message[7]:='      BY...';
  651.   message[9]:='';
  652.  message[10]:='';
  653.   for loop2:=1 to 7 do BEGIN
  654.     For loop1:=1 to length (message[loop2]) do BEGIN
  655.       doletter (message[loop2][loop1],loop1*17,loop2*17);
  656.       dir:=not(dir);
  657.     END;
  658.     for loop1:=1 to jump do move_em_out(jump,6);
  659.   END;
  660.  
  661.   eye_popper;
  662.   For loop1:=1 to 7 do
  663.     show (0,loop1*17,message[loop1]);
  664.   fadeouttext;
  665.   flip (vaddr2,vaddr);
  666.   flip (vaddr,vga);
  667.  
  668.   for loop1:=1 to 8 do
  669.     pal (loop1,arbpal[loop1,1],arbpal[loop1,2],arbpal[loop1,3]);
  670.   message[1]:='   TUNING...';
  671.   For loop1:=1 to length (message[1]) do BEGIN
  672.     if message[1][loop1]='.' then for loop2:=1 to 20 do
  673.       move_em_out(jump,6);
  674.     doletter (message[1][loop1],loop1*17,100);
  675.     dir:=not(dir);
  676.   END;
  677.   for loop1:=1 to jump do move_em_out(jump,6);
  678.  
  679.   eye_popper;
  680.   show (0,100,message[1]);
  681.   fadeouttext;
  682.  
  683.   static;
  684.  
  685.   freemem (vir2,sizeof (vir2^));
  686. END;
  687.  
  688.  
  689. BEGIN
  690.   clrscr;
  691.   writeln ('Hi there ... welcome to the seventeenth Asphyxia VGA Trainer ... and');
  692.   writeln ('the last one on demo effects for a while ... I am going to be doing');
  693.   writeln ('more work on the theory aspect in future trainers.');
  694.   writeln;
  695.   writeln ('This is an effect I first saw in an Extreme demo, and features ''Pixel');
  696.   writeln ('Text'', with various dots forming letters. Also included are some crossfades');
  697.   writeln ('and a static routine.');
  698.   writeln;
  699.   writeln ('Check out the GFX3 unit for a faster putpixel...');
  700.   writeln;
  701.   writeln ('The tank was drawn by Fubar a while ago when he was starting to learn');
  702.   writeln ('3D Studio. The font I found somewhere on my hard drive.');
  703.   writeln;
  704.   writeln;
  705.   writeln ('Hit any key to continue ...');
  706.   readkey;
  707.   setmcga;
  708.   setupvirtual;
  709.   play;
  710.   settext;
  711.   shutdown;
  712.   Writeln ('All done. This concludes the seventeenth sample program in the ASPHYXIA');
  713.   Writeln ('Training series. You may reach DENTHOR under the names of GRANT');
  714.   Writeln ('SMITH/DENTHOR/ASPHYXIA on the ASPHYXIA BBS.I also occasinally read');
  715.   Writeln ('RSAProg, comp.lang.pascal and comp.sys.ibm.pc.demos. E-mail me at :');
  716.   Writeln ('    denthor@beastie.cs.und.ac.za');
  717.   Writeln ('The numbers are available in the main text. You may also write to me at:');
  718.   Writeln ('             Grant Smith');
  719.   Writeln ('             P.O. Box 270');
  720.   Writeln ('             Kloof');
  721.   Writeln ('             3640');
  722.   Writeln ('             Natal');
  723.   Writeln ('             South Africa');
  724.   Writeln ('I hope to hear from you soon!');
  725.   Writeln; Writeln;
  726.   Write   ('Hit any key to exit ...');
  727.   readkey;
  728. END.Unit GFX3;
  729.  
  730.  
  731. INTERFACE
  732.  
  733. USES crt;
  734. CONST VGA = $A000;
  735.  
  736. TYPE Virtual = Array [1..64000] of byte;  { The size of our Virtual Screen }
  737.      VirtPtr = ^Virtual;                  { Pointer to the virtual screen }
  738.  
  739. VAR Virscr : VirtPtr;                     { Our first Virtual screen }
  740.     Vaddr  : word;                        { The segment of our virtual screen}
  741.     Scr_Ofs : Array[0..199] of Word;
  742.  
  743. Procedure SetMCGA;
  744.    { This procedure gets you into 320x200x256 mode. }
  745. Procedure SetText;
  746.    { This procedure returns you to text mode.  }
  747. Procedure Cls (Where:word;Col : Byte);
  748.    { This clears the screen to the specified color }
  749. Procedure SetUpVirtual;
  750.    { This sets up the memory needed for the virtual screen }
  751. Procedure ShutDown;
  752.    { This frees the memory used by the virtual screen }
  753. procedure flip(source,dest:Word);
  754.    { This copies the entire screen at "source" to destination }
  755. Procedure Pal(Col,R,G,B : Byte);
  756.    { This sets the Red, Green and Blue values of a certain color }
  757. Procedure GetPal(Col : Byte; Var R,G,B : Byte);
  758.   { This gets the Red, Green and Blue values of a certain color }
  759. procedure WaitRetrace;
  760.    {  This waits for a vertical retrace to reduce snow on the screen }
  761. Procedure Hline (x1,x2,y:word;col:byte;where:word);
  762.    { This draws a horizontal line from x1 to x2 on line y in color col }
  763. Procedure Line(a,b,c,d:integer;col:byte;where:word);
  764.   { This draws a solid line from a,b to c,d in colour col }
  765. Procedure DrawPoly(x1,y1,x2,y2,x3,y3,x4,y4:integer;color:byte;where:word);
  766.    { This draw a polygon with 4 points at x1,y1 , x2,y2 , x3,y3 , x4,y4
  767.      in color col }
  768. Function rad (theta : real) : real;
  769.    {  This calculates the degrees of an angle }
  770. Procedure Putpixel (X,Y : Integer; Col : Byte; where:word);
  771.    { This puts a pixel on the screen by writing directly to memory. }
  772. Function Getpixel (X,Y : Integer; where:word) :Byte;
  773.    { This gets the pixel on the screen by reading directly to memory. }
  774. Procedure LoadCEL (FileName :  string; ScrPtr : pointer);
  775.   { This loads the cel 'filename' into the pointer scrptr }
  776. Procedure LoadPal (FileName : string);
  777.   { This loads in an Autodesk Animator V1 pallette file }
  778.  
  779. IMPLEMENTATION
  780.  
  781. {──────────────────────────────────────────────────────────────────────────}
  782. Procedure SetMCGA;  { This procedure gets you into 320x200x256 mode. }
  783. BEGIN
  784.   asm
  785.      mov        ax,0013h
  786.      int        10h
  787.   end;
  788. END;
  789.  
  790. {──────────────────────────────────────────────────────────────────────────}
  791. Procedure SetText;  { This procedure returns you to text mode.  }
  792. BEGIN
  793.   asm
  794.      mov        ax,0003h
  795.      int        10h
  796.   end;
  797. END;
  798.  
  799. {──────────────────────────────────────────────────────────────────────────}
  800. Procedure Cls (Where:word;Col : Byte); assembler;
  801.    { This clears the screen to the specified color }
  802. asm
  803.    push    es
  804.    mov     cx, 32000;
  805.    mov     es,[where]
  806.    xor     di,di
  807.    mov     al,[col]
  808.    mov     ah,al
  809.    rep     stosw
  810.    pop     es
  811. End;
  812.  
  813. {──────────────────────────────────────────────────────────────────────────}
  814. Procedure SetUpVirtual;
  815.    { This sets up the memory needed for the virtual screen }
  816. BEGIN
  817.   GetMem (VirScr,64000);
  818.   vaddr := seg (virscr^);
  819. END;
  820.  
  821. {──────────────────────────────────────────────────────────────────────────}
  822. Procedure ShutDown;
  823.    { This frees the memory used by the virtual screen }
  824. BEGIN
  825.   FreeMem (VirScr,64000);
  826. END;
  827.  
  828. {──────────────────────────────────────────────────────────────────────────}
  829. procedure flip(source,dest:Word); assembler;
  830.   { This copies the entire screen at "source" to destination }
  831. asm
  832.   push    ds
  833.   mov     ax, [Dest]
  834.   mov     es, ax
  835.   mov     ax, [Source]
  836.   mov     ds, ax
  837.   xor     si, si
  838.   xor     di, di
  839.   mov     cx, 32000
  840.   rep     movsw
  841.   pop     ds
  842. end;
  843.  
  844. {──────────────────────────────────────────────────────────────────────────}
  845. Procedure Pal(Col,R,G,B : Byte); assembler;
  846.   { This sets the Red, Green and Blue values of a certain color }
  847. asm
  848.    mov    dx,3c8h
  849.    mov    al,[col]
  850.    out    dx,al
  851.    inc    dx
  852.    mov    al,[r]
  853.    out    dx,al
  854.    mov    al,[g]
  855.    out    dx,al
  856.    mov    al,[b]
  857.    out    dx,al
  858. end;
  859.  
  860. {──────────────────────────────────────────────────────────────────────────}
  861. Procedure GetPal(Col : Byte; Var R,G,B : Byte);
  862.   { This gets the Red, Green and Blue values of a certain color }
  863. Var
  864.    rr,gg,bb : Byte;
  865. Begin
  866.    asm
  867.       mov    dx,3c7h
  868.       mov    al,col
  869.       out    dx,al
  870.  
  871.       add    dx,2
  872.  
  873.       in     al,dx
  874.       mov    [rr],al
  875.       in     al,dx
  876.       mov    [gg],al
  877.       in     al,dx
  878.       mov    [bb],al
  879.    end;
  880.    r := rr;
  881.    g := gg;
  882.    b := bb;
  883. end;
  884.  
  885. {──────────────────────────────────────────────────────────────────────────}
  886. procedure WaitRetrace; assembler;
  887.   {  This waits for a vertical retrace to reduce snow on the screen }
  888. label
  889.   l1, l2;
  890. asm
  891.     mov dx,3DAh
  892. l1:
  893.     in al,dx
  894.     and al,08h
  895.     jnz l1
  896. l2:
  897.     in al,dx
  898.     and al,08h
  899.     jz  l2
  900. end;
  901.  
  902. {──────────────────────────────────────────────────────────────────────────}
  903. Procedure Hline (x1,x2,y:word;col:byte;where:word); assembler;
  904.   { This draws a horizontal line from x1 to x2 on line y in color col }
  905. asm
  906.   mov   ax,where
  907.   mov   es,ax
  908.   mov   ax,y
  909.   mov   di,ax
  910.   shl   ax,8
  911.   shl   di,6
  912.   add   di,ax
  913.   add   di,x1
  914.  
  915.   mov   al,col
  916.   mov   ah,al
  917.   mov   cx,x2
  918.   sub   cx,x1
  919.   shr   cx,1
  920.   jnc   @start
  921.   stosb
  922. @Start :
  923.   rep   stosw
  924. end;
  925.  
  926. {──────────────────────────────────────────────────────────────────────────}
  927. Procedure Line(a,b,c,d:integer;col:byte;where:word);
  928.   { This draws a solid line from a,b to c,d in colour col }
  929.   function sgn(a:real):integer;
  930.   begin
  931.        if a>0 then sgn:=+1;
  932.        if a<0 then sgn:=-1;
  933.        if a=0 then sgn:=0;
  934.   end;
  935. var i,s,d1x,d1y,d2x,d2y,u,v,m,n:integer;
  936. begin
  937.      u:= c - a;
  938.      v:= d - b;
  939.      d1x:= SGN(u);
  940.      d1y:= SGN(v);
  941.      d2x:= SGN(u);
  942.      d2y:= 0;
  943.      m:= ABS(u);
  944.      n := ABS(v);
  945.      IF NOT (M>N) then
  946.      BEGIN
  947.           d2x := 0 ;
  948.           d2y := SGN(v);
  949.           m := ABS(v);
  950.           n := ABS(u);
  951.      END;
  952.      s := m shr 1;
  953.      FOR i := 0 TO m DO
  954.      BEGIN
  955.           putpixel(a,b,col,where);
  956.           s := s + n;
  957.           IF not (s<m) THEN
  958.           BEGIN
  959.                s := s - m;
  960.                a:= a + d1x;
  961.                b := b + d1y;
  962.           END
  963.           ELSE
  964.           BEGIN
  965.                a := a + d2x;
  966.                b := b + d2y;
  967.           END;
  968.      end;
  969. END;
  970.  
  971.  
  972. {──────────────────────────────────────────────────────────────────────────}
  973. Procedure DrawPoly(x1,y1,x2,y2,x3,y3,x4,y4:integer;color:byte;where:word);
  974.   { This draw a polygon with 4 points at x1,y1 , x2,y2 , x3,y3 , x4,y4
  975.     in color col }
  976. var
  977.   x:integer;
  978.   mny,mxy:integer;
  979.   mnx,mxx,yc:integer;
  980.   mul1,div1,
  981.   mul2,div2,
  982.   mul3,div3,
  983.   mul4,div4:integer;
  984.  
  985. begin
  986.   mny:=y1; mxy:=y1;
  987.   if y2<mny then mny:=y2;
  988.   if y2>mxy then mxy:=y2;
  989.   if y3<mny then mny:=y3;
  990.   if y3>mxy then mxy:=y3;    { Choose the min y mny and max y mxy }
  991.   if y4<mny then mny:=y4;
  992.   if y4>mxy then mxy:=y4;
  993.  
  994.   if mny<0 then mny:=0;
  995.   if mxy>199 then mxy:=199;
  996.   if mny>199 then exit;
  997.   if mxy<0 then exit;        { Verticle range checking }
  998.  
  999.   mul1:=x1-x4; div1:=y1-y4;
  1000.   mul2:=x2-x1; div2:=y2-y1;
  1001.   mul3:=x3-x2; div3:=y3-y2;
  1002.   mul4:=x4-x3; div4:=y4-y3;  { Constansts needed for intersection calc }
  1003.  
  1004.   for yc:=mny to mxy do
  1005.     begin
  1006.       mnx:=320;
  1007.       mxx:=-1;
  1008.       if (y4>=yc) or (y1>=yc) then
  1009.         if (y4<=yc) or (y1<=yc) then   { Check that yc is between y1 and y4 }
  1010.           if not(y4=y1) then
  1011.             begin
  1012.               x:=(yc-y4)*mul1 div div1+x4; { Point of intersection on x axis }
  1013.               if x<mnx then
  1014.                 mnx:=x;
  1015.               if x>mxx then
  1016.                 mxx:=x;       { Set point as start or end of horiz line }
  1017.             end;
  1018.       if (y1>=yc) or (y2>=yc) then
  1019.         if (y1<=yc) or (y2<=yc) then   { Check that yc is between y1 and y2 }
  1020.           if not(y1=y2) then
  1021.             begin
  1022.               x:=(yc-y1)*mul2 div div2+x1; { Point of intersection on x axis }
  1023.               if x<mnx then
  1024.                 mnx:=x;
  1025.               if x>mxx then
  1026.                 mxx:=x;       { Set point as start or end of horiz line }
  1027.             end;
  1028.       if (y2>=yc) or (y3>=yc) then
  1029.         if (y2<=yc) or (y3<=yc) then   { Check that yc is between y2 and y3 }
  1030.           if not(y2=y3) then
  1031.             begin
  1032.               x:=(yc-y2)*mul3 div div3+x2; { Point of intersection on x axis }
  1033.               if x<mnx then
  1034.                 mnx:=x;
  1035.               if x>mxx then
  1036.                 mxx:=x;       { Set point as start or end of horiz line }
  1037.             end;
  1038.       if (y3>=yc) or (y4>=yc) then
  1039.         if (y3<=yc) or (y4<=yc) then   { Check that yc is between y3 and y4 }
  1040.           if not(y3=y4) then
  1041.             begin
  1042.               x:=(yc-y3)*mul4 div div4+x3; { Point of intersection on x axis }
  1043.               if x<mnx then
  1044.                 mnx:=x;
  1045.               if x>mxx then
  1046.                 mxx:=x;       { Set point as start or end of horiz line }
  1047.             end;
  1048.       if mnx<0 then
  1049.         mnx:=0;
  1050.       if mxx>319 then
  1051.         mxx:=319;          { Range checking on horizontal line }
  1052.       if mnx<=mxx then
  1053.         hline (mnx,mxx,yc,color,where);   { Draw the horizontal line }
  1054.     end;
  1055.   end;
  1056.  
  1057. {──────────────────────────────────────────────────────────────────────────}
  1058. Function rad (theta : real) : real;
  1059.   {  This calculates the degrees of an angle }
  1060. BEGIN
  1061.   rad := theta * pi / 180
  1062. END;
  1063.  
  1064. {──────────────────────────────────────────────────────────────────────────}
  1065. Procedure Putpixel (X,Y : Integer; Col : Byte; where:word); assembler;
  1066.   { This puts a pixel on the screen by writing directly to memory. }
  1067. asm
  1068.    mov  ax,where
  1069.    mov  es,ax
  1070.    mov  bx,[y]
  1071.    shl  bx,1
  1072.    mov  di,word ptr [Scr_Ofs + bx]
  1073.    add  di,[x]
  1074.    mov  al,[col]
  1075.    mov  es:[di],al
  1076. end;
  1077.  
  1078.  
  1079. {──────────────────────────────────────────────────────────────────────────}
  1080. Function Getpixel (X,Y : Integer; where:word):byte; assembler;
  1081.   { This puts a pixel on the screen by writing directly to memory. }
  1082. asm
  1083.    mov  ax,where
  1084.    mov  es,ax
  1085.    mov  bx,[y]
  1086.    shl  bx,1
  1087.    mov  di,word ptr [Scr_Ofs + bx]
  1088.    add  di,[x]
  1089.    mov  al,es:[di]
  1090. end;
  1091.  
  1092. {──────────────────────────────────────────────────────────────────────────}
  1093. Procedure LoadCEL (FileName :  string; ScrPtr : pointer);
  1094.   { This loads the cel 'filename' into the pointer scrptr }
  1095. var
  1096.   Fil : file;
  1097.   Buf : array [1..1024] of byte;
  1098.   BlocksRead, Count : word;
  1099. begin
  1100.   assign (Fil, FileName);
  1101.   reset (Fil, 1);
  1102.   BlockRead (Fil, Buf, 800);    { Read and ignore the 800 byte header }
  1103.   Count := 0;
  1104.   BlocksRead := $FFFF;
  1105.   while (not eof (Fil)) and (BlocksRead <> 0) do begin
  1106.     BlockRead (Fil, mem [seg (ScrPtr^): ofs (ScrPtr^) + Count], 1024, BlocksRead);
  1107.     Count := Count + 1024;
  1108.   end;
  1109.   close (Fil);
  1110. end;
  1111.  
  1112.  
  1113. procedure LoadPal (FileName : string);
  1114. var
  1115.   F:file;
  1116.   loop1:integer;
  1117.   pall:array[0..255,1..3] of byte;
  1118. begin
  1119.   assign (F, FileName);
  1120.   reset (F,1);
  1121.   blockread (F, pall,768);
  1122.   close (F);
  1123.   for loop1 := 0 to 255 do
  1124.     Pal(loop1,pall[loop1,1],pall[loop1,2],pall[loop1,3]);
  1125. end;
  1126.  
  1127.  
  1128. VAR Loop1:integer;
  1129.  
  1130. BEGIN
  1131.   For Loop1 := 0 to 199 do
  1132.     Scr_Ofs[Loop1] := Loop1 * 320;
  1133. END.